using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OhioState.AssetManaged;
using OhioState.Graphics;
using OhioState.Graphics.Proxy;

namespace OhioState.Controls
{
    public partial class MaterialControl : UserControl
    {
        //
        // Material currently being controlled
        //
        private MaterialProxy material;

        //
        // Delegate for Material Control
        //
        private delegate void MaterialHandler(MaterialProxy mat);
        public MaterialControl()
        {
            InitializeComponent();

            //
            // Initialize asset manager control and events
            //
            assetManagerDropDownControl1.Init(typeof(ShaderProgram));

            //
            // Set up event handler for selection changed event
            //
            assetManagerDropDownControl1.SelectedEvent += new IAssetManagedHandler(assetManagerControl_SelectedEvent);

            // Set up lights
            lightAssetManagerDropDownControl.Init(typeof(LightCollectionProxy));
            lightAssetManagerDropDownControl.SelectedEvent += new IAssetManagedHandler(lightDropDownControlHandler);
        }

        #region Public properties

        //
        // Public properties
        //
        public MaterialProxy Material
        {
            get { return material; }
        }

        //
        // Set the focus of this control to a new Material.  
        private void SetMaterial_thisThread(MaterialProxy mat)
        {
            material = null;
            //
            // Toggle Enabled based on whether the material is null or not
            //
            if (mat == null)
            {
                this.Enabled = false;
            }
            else
            {
                this.Enabled = true;

                //
                // Populate control with Material values
                //
                switch (mat.Compositor.Blending)
                {
                    case BlendMode.OFF:
                        blendComboBox.SelectedItem = "Off";
                        break;
                    case BlendMode.ADD:
                        blendComboBox.SelectedItem = "Add";
                        break;
                    case BlendMode.OVER:
                        blendComboBox.SelectedItem = "Over";
                        break;
                    case BlendMode.MAX:
                        blendComboBox.SelectedItem = "Max";
                        break;
                    case BlendMode.MIN:
                        blendComboBox.SelectedItem = "Min";
                        break;
                    case BlendMode.REPLACE:
                        blendComboBox.SelectedItem = "Replace";
                        break;
                    case BlendMode.TRANSPARENT:
                        blendComboBox.SelectedItem = "Transparent";
                        break;
                }
                
                switch (mat.Compositor.AlphaTest)
                {
                    case AlphaMode.EQUAL:
                        alphaComboBox.SelectedItem = "Equal";
                        break;
                    case AlphaMode.GREATER_THAN:
                        alphaComboBox.SelectedItem = "GreaterThan";
                        break;
                    case AlphaMode.GREATER_THAN_OR_EQUAL:
                        alphaComboBox.SelectedItem = "GreaterThanOrEqual";
                        break;
                    case AlphaMode.LESS_THAN:
                        alphaComboBox.SelectedItem = "LessThan";
                        break;
                    case AlphaMode.LESS_THAN_OR_EQUAL:
                        alphaComboBox.SelectedItem = "LessThanOrEqual";
                        break;
                    case AlphaMode.NOT_EQUAL:
                        alphaComboBox.SelectedItem = "NotEqual";
                        break;
                    case AlphaMode.OFF:
                        alphaComboBox.SelectedItem = "Off";
                        break;
                }
                if (mat.Compositor.DepthTest == DepthMode.ON)
                    depthTestCheckBox.Checked = true;
                else
                    depthTestCheckBox.Checked = false;

                assetManagerDropDownControl1.SelectItem(mat.Shader as ShaderProgram);
                checkBox1.Checked = mat.ApplyLighting;
                //////
                lightAssetManagerDropDownControl.SelectItem(mat.LightCollection as LightCollectionProxy);
            }
            material = mat;
        }
        //
        // Force the event to get called on the proper thread.  The DataGridView complains if you try
        //  to use it on the wrong thread.
        //
        public void SetMaterial(MaterialProxy mat)
        {
            MaterialHandler newEvent = new MaterialHandler(SetMaterial_thisThread);
            object[] args = new object[1];
            args[0] = mat;
            //
            // We need to make sure these methods are executed on the correct thread.
            //
           // this.Invoke(newEvent, args);

            try
            {
                if (this.InvokeRequired)
                    this.Invoke(newEvent, args);
                else
                    newEvent(mat);
            }
            catch { }
        }

        #endregion

        //
        // Selected event handler
        //
        private void assetManagerControl_SelectedEvent(IAssetManaged obj)
        {
            if (material != null)
            {
                material.Shader = (IShaderProgram)obj;
            }
        }

        private void uvvButton_Click(object sender, EventArgs e)
        {
            if (material != null)
            {
                if (material.Shader != null)
                {
                    material.BeginManipulation();
                    Dictionary<String, UniformVariableValues> uvvs = material.UniformVariableValues;
                    UVVDialog uvvDialog = new UVVDialog();
                    uvvDialog.ShowAndInit(uvvs);
                    material.EndManipulation();
                }
            }
        }

        private void blendComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (material != null)
            {
                material.BeginManipulation();
                switch ((String)blendComboBox.SelectedItem)
                {
                    case "Add":
                        material.Compositor.Blending = BlendMode.ADD;
                        break;
                    case "Over":
                        material.Compositor.Blending = BlendMode.OVER;
                        break;
                    case "Max":
                        material.Compositor.Blending = BlendMode.MAX;
                        break;
                    case "Min":
                        material.Compositor.Blending = BlendMode.MIN;
                        break;
                    case "Replace":
                        material.Compositor.Blending = BlendMode.REPLACE;
                        break;
                    case "Transparent":
                        material.Compositor.Blending = BlendMode.TRANSPARENT;
                        break;
                }
                material.EndManipulation();
            }
        }

        private void alphaComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (material != null)
            {
                material.BeginManipulation();
                switch ((String)alphaComboBox.SelectedItem)
                {
                    case "Equal":
                        material.Compositor.AlphaTest = AlphaMode.EQUAL;
                        break;
                    case "GreaterThan":
                        material.Compositor.AlphaTest = AlphaMode.GREATER_THAN;
                        break;
                    case "GreaterThanOrEqual":
                        material.Compositor.AlphaTest = AlphaMode.GREATER_THAN_OR_EQUAL;
                        break;
                    case "LessThan":
                        material.Compositor.AlphaTest = AlphaMode.LESS_THAN;
                        break;
                    case "LessThanOrEqual":
                        material.Compositor.AlphaTest = AlphaMode.LESS_THAN_OR_EQUAL;
                        break;
                    case "NotEqual":
                        material.Compositor.AlphaTest = AlphaMode.NOT_EQUAL;
                        break;
                    case "Off":
                        material.Compositor.AlphaTest = AlphaMode.OFF;
                        break;
                }
                material.EndManipulation();
            }
        }

        private void frontMatButton_Click(object sender, EventArgs e)
        {
            if (material != null)
            {
                MaterialColorDialog mcd = new MaterialColorDialog();
                mcd.ShowAndInit(material, true);
            }
        }

        private void backMatButton_Click(object sender, EventArgs e)
        {
            if (material != null)
            {
                MaterialColorDialog mcd = new MaterialColorDialog();
                mcd.ShowAndInit(material, false);
            }
        }

        private void currentColorButton_Click(object sender, EventArgs e)
        {
            if (material != null)
            {
                CurrentColorDialog ccd = new CurrentColorDialog();
                ccd.ShowAndInit(material);
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (material != null)
            {
                material.BeginManipulation();
                if (checkBox1.Checked)
                    material.ApplyLighting = true;
                else
                    material.ApplyLighting = false;
                material.EndManipulation();
            }
        }

        private ComponentControls.LightingDialog lightingDialog;  
        private void lightControlButton_Click(object sender, EventArgs e)
        {
            if (material == null) return;

            //if (lightingDialog == null || lightingDialog.IsDisposed)
            {
                lightingDialog = new ComponentControls.LightingDialog(material);
            }
            //lightingDialog.Show();
        }

        private void lightDropDownControlHandler(IAssetManaged obj)
        {
            if (material != null)
            {
                material.BeginManipulation();
                material.LightCollection = (LightCollectionProxy)obj;
                material.EndManipulation();
            }
        }

        private void depthTestCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (material == null) return;
            // TODO: remove the cast!!!
            RasterOpsProxy rasterOps = material.Compositor as RasterOpsProxy;
            if (depthTestCheckBox.Checked)
                rasterOps.DepthTest = DepthMode.ON;
            else
                rasterOps.DepthTest = DepthMode.OFF;
            material.Compositor = rasterOps;
        }
    }
}
